Skip to content

Python: support MCP skills of mcp-resource-template type#6648

Closed
vaibhav-patel wants to merge 4 commits into
microsoft:mainfrom
vaibhav-patel:fix/6118-mcp-resource-template-skills
Closed

Python: support MCP skills of mcp-resource-template type#6648
vaibhav-patel wants to merge 4 commits into
microsoft:mainfrom
vaibhav-patel:fix/6118-mcp-resource-template-skills

Conversation

@vaibhav-patel

Copy link
Copy Markdown
Contributor

Summary

Adds support for the mcp-resource-template skill kind to the MCP skills source,
addressing #6118.

Per the SEP-2640 binding of Agent Skills Discovery v0.2.0, an mcp-resource-template
entry in skill://index.json omits name and carries an RFC 6570 URI template in
url (e.g. skill://docs/{product}/SKILL.md) that resolves to a SKILL.md resource
once its variables are bound. One template represents a family of skills — one per
variable binding. (Mirrors the .NET McpSkillIndexEntry contract in
Microsoft.Agents.AI.Mcp.)

Changes

  • New MCPSkillResourceTemplate (exported, experimental MCP_SKILLS):
    • variables — template variable names (RFC 6570 Level-1).
    • expand(variables) — simple string expansion; values percent-encoded so they can't
      inject path segments/schemes; errors on missing variables.
    • materialize(*, name, variables, description=None) — returns a concrete MCPSkill
      reusing existing fetch machinery.
  • MCPSkillsSource.get_resource_templates() — surfaces template entries separately
    from get_skills(). Concrete skills are not auto-materialized at discovery because the
    variable values aren't in the index; callers bind them explicitly. get_skills()
    behavior is unchanged.
  • Tests: 17 new covering variable extraction, expansion/encoding/error paths,
    materialize, discovery, and end-to-end resolution.

Open design question (for maintainers)

Auto-enumerating concrete skills during discovery requires a source of variable values
(host/user config, or resources/templates/list + completion). That decision is left open
intentionally; this PR provides the parsing, validation, and explicit-materialization
primitives. Happy to extend with an auto-materialization strategy once the sourcing
approach is decided. This also keeps Python aligned with .NET #6117, which currently skips
templates as well.

Verification

  • uv run pytest packages/core/tests/core/test_mcp_skills.py → 68 passed.
  • ruff check / ruff format --check clean on changed files.

Addresses #6118.

Add support for the `mcp-resource-template` skill kind in the MCP skills
source. Per the SEP-2640 binding of the Agent Skills Discovery v0.2.0
schema, an `mcp-resource-template` index entry omits `name` and carries an
RFC 6570 URI template in `url` (e.g. `skill://docs/{product}/SKILL.md`)
that resolves to a `SKILL.md` resource once its variables are bound. One
template stands in for a family of skills, one per variable binding.

Introduce `MCPSkillResourceTemplate`, which parses such an entry, exposes
its template variables, and materializes a concrete `MCPSkill` from an
explicit variable binding (RFC 6570 Level-1 simple string expansion, with
values percent-encoded so they cannot inject extra path segments).

`MCPSkillsSource` gains `get_resource_templates()`, which surfaces template
entries separately from `get_skills()`. Concrete skills are not
auto-materialized during discovery because the template variable values are
not part of the index; callers bind them explicitly via `materialize()`.
This keeps `get_skills()` behavior unchanged (template entries remain
excluded from the concrete skill list).

Addresses microsoft#6118.
Copilot AI review requested due to automatic review settings June 20, 2026 11:30
@moonbox3 moonbox3 added the python Usage: [Issues, PRs], Target: Python label Jun 20, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Python support for MCP skill index entries of type mcp-resource-template (RFC 6570 URI templates) by introducing a resource-template abstraction and a parallel discovery path that surfaces templates separately from concrete skills.

Changes:

  • Introduces MCPSkillResourceTemplate with variable extraction, safe URI expansion (percent-encoding), and explicit materialize() to produce concrete MCPSkill instances.
  • Extends MCPSkillsSource with get_resource_templates() to discover template entries without auto-materializing skills.
  • Adds unit tests covering template parsing/expansion/materialization and discovery behavior, and exports the new type from agent_framework.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
python/packages/core/agent_framework/_skills.py Adds MCPSkillResourceTemplate and MCPSkillsSource.get_resource_templates() to support discovery/materialization of mcp-resource-template entries.
python/packages/core/agent_framework/init.py Exports MCPSkillResourceTemplate from the package surface (__all__ + imports).
python/packages/core/tests/core/test_mcp_skills.py Adds tests for template behavior and for discovering templates separately from concrete skills.

Comment on lines +3652 to +3657
if not url_template or not url_template.strip():
raise ValueError("url_template cannot be empty.")

self.description = description
self.url_template = url_template
self._client = client

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks — now validating the template and raising ValueError on unsupported RFC 6570 operators/modifiers and unbalanced braces, so behavior matches the contract; done in 100e961.

Comment on lines +709 to +713
def test_empty_url_template_raises(self) -> None:
client = AsyncMock()
with pytest.raises(ValueError, match="url_template cannot be empty"):
MCPSkillResourceTemplate(description="docs", url_template=" ", client=client)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added tests for the rejection path ({+product}, {product:3}, unbalanced braces) in 100e961.

…emplate

MCPSkillResourceTemplate previously accepted URL templates containing
RFC 6570 operators/modifiers (e.g. {+var}, {var:3}, {var*}) or unbalanced
braces. Because the variable regex only matches Level-1 {var}, expand()
left such expressions untouched and materialize() produced an MCPSkill
pointing at a still-templated URI, contradicting the documented contract
that says those expressions are rejected.

Validate the template at construction via _validate_uri_template, raising
a clear ValueError on operators/modifiers, list expressions, and
unbalanced/empty braces, so behavior matches the contract. The supported
Level-1 {var} path is unchanged. Add focused tests covering the rejection
path and confirming a normal {var} template still works.
@SergeyMenshykh

Copy link
Copy Markdown
Contributor

Hi @vaibhav-patel, thanks for this PR. We've considered supporting skills of the mcp-resource-template type but postponed it until the spec has finalized the design for this type.

Please let us know your scenario so we can take it into account when adding support for this skill type. Closing the PR for now

@SergeyMenshykh SergeyMenshykh added the skills Usage: [Issues, PRs], Target: skills related features label Jun 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python skills Usage: [Issues, PRs], Target: skills related features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants